//class that represent a vector of bits
//internally the implementation it is based on word32 and C++ vector
//Hence it is optimized for many bits and also for adding more bits dynamically
#ifndef BV32
#define BV32

#include "word32.h"
#include <vector>

class BitVector32 {
 private:
  std::vector<word32> bitVec; //the vector itself
  unsigned long nbrOfBits; //the number of bits in the vector
  unsigned nbrOfWords; //the number of words required to store nbrOfBits bits

 public:
  //default constructor, empty vector
  BitVector32(){
    nbrOfBits=0;
    nbrOfWords=0;
  }

  //constructor that contains N bits, all zero
  //assumes N>0
  BitVector32(int N){
    nbrOfBits=N;
    nbrOfWords=((N-1)>>5)+1;
    bitVec.resize(nbrOfWords);
  }
  
  //constructor that takes a binary string as input
  //the size of the vector will be equal to the length of the string
  //it is assumed that leas significant bit first in the string
  BitVector32(std::string initString);

  //return the number of bits in the string
  inline unsigned long length(){
    return nbrOfBits;
  } 

  //converts the bitVector to a string 
  //binary representation, LSB first
  std::string toBinStringLSB();

  //converts the bitVector to a string 
  //binary representation, MSB first
  std::string toBinStringMSB();

  //converts the bitVector to a string 
  //hexadecimal representation, LSB first
  std::string toHexStringLSB();

  //converts the bitVector to a string 
  //hexadecimal representation, MSB first
  std::string toHexStringMSB();

  //get bit at position k
  //observe that it is not tested that k<nbrOfBits
  inline int getBit(int k){
    //bit k in the bitvector is located in word k/32
    //the final 5 bits get the position in this word
    return bitVec[k>>5].getBit(k&0x1f);
  }

 
  //set bit at position k to 1
  //observe that it is not tested that k<nbrOfBits
  inline void setBit(int k){
    //bit k in the bitvector is located in word k/32
    //the final 5 bits of k get the position in this word
    bitVec[k>>5].setBit(k&0x1f);
  }

  //set bit at position k to 0
  //observe that it is not tested that k<nbrOfBits
  inline void clearBit(int k){
    //bit k in the bitvector is located in word k/32
    //the final 5 bits get the position in this word
    bitVec[k>>5].clearBit(k&0x1f);
  }

  //set bit at position k to he value given by val
  //observe that it is not tested that k<nbrOfBits
  inline void setVal(int k,int val){
    //bit k in the bitvector is located in word k/32
    //the final 5 bits get the position in this word
    if(val==0)
      bitVec[k>>5].clearBit(k&0x1f);
    else 
      bitVec[k>>5].setBit(k&0x1f);
  }

  //the operator or, it is assumed that the vectors have the same length
  //bitwise or is applied
  inline void orOp(const BitVector32& operand){
    for(unsigned i=0;i<nbrOfWords;i++)
      bitVec[i].orOp(operand.bitVec[i]);
  }

  //the operator and, it is assumed that the vectors have the same length
  //bitwise and is applied
  inline void andOp(const BitVector32& operand){
    for(unsigned i=0;i<nbrOfWords;i++)
      bitVec[i].andOp(operand.bitVec[i]);
  }

  //the operator xor, it is assumed that the vectors have the same length
  //bitwise xor is applied
  inline void xorOp(const BitVector32& operand){
    for(unsigned i=0;i<nbrOfWords;i++)
      bitVec[i].xorOp(operand.bitVec[i]);
  }
 
  //the operator not, it is assumed that the vectors have the same length
  //bitwise not is applied
  inline void notOp(){
    for(unsigned i=0;i<nbrOfWords;i++)
      bitVec[i].notOp();
  }
 
  //append a bit to the end of the vector
  void appendBit(int val);

  //append a word to the end of the vector
  void appendWord32(word32 w);

  //the hamming weight of the vector
  inline unsigned long weight(){
    unsigned long w=0;
    for(unsigned i=0;i<nbrOfWords;i++)
      w+=bitVec[i].weight();
    return w;
  }

};

#endif
